/*
 * @Author: LVGRAPE
 * @LastEditors: LVGRAPE
 */
#include <windows.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <wchar.h>
#include <stdio.h>
#include <errno.h>
#include "uart.h"

HANDLE hSerial;
void ErrorExit(char *msg, DWORD errorCode);
int uart_win_init(char *port_name, uint32_t baudrate)
{

    DCB dcbSerialParams = {0};
    COMMTIMEOUTS timeouts = {0};

    wchar_t portName[20];
    swprintf(portName, 20, L"\\\\.\\%S", port_name);
    LPCWSTR filename = portName;

    // 打开串口
    hSerial = CreateFile(
        port_name,                    // 串口名称，根据实际情况修改
        GENERIC_READ | GENERIC_WRITE, // 读写访问
        0,                            // 不共享
        NULL,                         // 默认安全属性
        OPEN_EXISTING,                // 打开现有文件
        0,                            // 默认属性
        NULL);                        // 不使用模板文件

    if (hSerial == INVALID_HANDLE_VALUE)
    {
        ErrorExit(port_name, GetLastError());
        return 1;
    }

    // 配置串口参数
    dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
    if (!GetCommState(hSerial, &dcbSerialParams))
    {
        ErrorExit(port_name, GetLastError());
        CloseHandle(hSerial);
        return 1;
    }
    switch (baudrate)
    {
    case 9600:
        dcbSerialParams.BaudRate = CBR_9600;
        break;
    case 115200:
        dcbSerialParams.BaudRate = CBR_115200;
        break;
    case 128000:
        dcbSerialParams.BaudRate = CBR_128000;
    case 256000:
        dcbSerialParams.BaudRate = CBR_256000;
        break;
    default:
        dcbSerialParams.BaudRate = CBR_115200;
        break;
    }
    dcbSerialParams.BaudRate = baudrate;
    dcbSerialParams.ByteSize = 8;
    dcbSerialParams.StopBits = ONESTOPBIT;
    dcbSerialParams.Parity = EVENPARITY;
    dcbSerialParams.fRtsControl = RTS_CONTROL_DISABLE;
    dcbSerialParams.fDtrControl = DTR_CONTROL_DISABLE;
    dcbSerialParams.fOutxCtsFlow = 0;
    dcbSerialParams.fOutxDsrFlow = 0;

    if (!SetCommState(hSerial, &dcbSerialParams))
    {
        fprintf(stderr, "Error setting serial port state\n");
        CloseHandle(hSerial);
        return 1;
    }

    // 设置超时
    timeouts.ReadIntervalTimeout = 2;        // “空闲超时”
    timeouts.ReadTotalTimeoutConstant = 1;   // 这是读操作的总超时常数。它指定了在读取操作开始之前可以等待的总时间（以毫秒为单位），而不考虑已经读取的字符数。
    timeouts.ReadTotalTimeoutMultiplier = 1; // 它指定了在读取每个字符时可以额外等待的时间（以毫秒为单位）
    timeouts.WriteTotalTimeoutConstant = 10; // 它指定了在写操作开始之前可以等待的总时间（以毫秒为单位）。
    timeouts.WriteTotalTimeoutMultiplier = 10;

    if (!SetCommTimeouts(hSerial, &timeouts))
    {
        ErrorExit(port_name, GetLastError());
        CloseHandle(hSerial);
        return 1;
    }
    // 设置缓冲区大小
    DWORD inBufferSize = 4096;  // 输入缓冲区大小（字节）
    DWORD outBufferSize = 4096; // 输出缓冲区大小（字节）

    if (!SetupComm(hSerial, inBufferSize, outBufferSize))
    {
        ErrorExit(port_name, GetLastError());
        CloseHandle(hSerial);
        return 1;
    }
    printf("Serial port %s opened successfully\n", port_name);
    return 0;
}
int uart_win_write(uint8_t *data, uint16_t len)
{
    DWORD bytesWritten;
    if (!WriteFile(hSerial, data, len, &bytesWritten, NULL))
    {
        // fprintf(stderr, "Error writing to serial port\n");
        // PrintLastError();
    }
    else
    {
        // printf("(%d)-> [ ",bytesWritten);
        // for(int i=0;i<bytesWritten;i++)
        //     printf("%02X ",data[i]);
        // printf("]\n");
        // printf("Wrote %d bytes to serial port\n", bytesWritten);
    }
    return bytesWritten;
}
int uart_win_read(uint8_t *data, uint16_t len)
{
    DWORD bytesRead;
    if (!ReadFile(hSerial, data, len, &bytesRead, NULL))
    {
        // fprintf(stderr, "Error reading from serial port\n");
        // PrintLastError();
    }
    else
    {
        // printf("(%d)<- [ ",bytesRead);
        // for(int i=0;i<bytesRead;i++)
        //     printf("%02X ",data[i]);
        // printf("]\n");
        // printf("Read %d bytes from serial port\n", bytesRead);
    }
    return bytesRead;
}
int uart_win_set_rts(int fcom, int level)
{
    if (!level)
        EscapeCommFunction(hSerial, SETRTS);
    else
        EscapeCommFunction(hSerial, CLRRTS);
}
int uart_win_clear()
{
    return PurgeComm(hSerial, PURGE_RXCLEAR | PURGE_RXABORT);
}
void ErrorExit(char *msg, DWORD errorCode)
{
    // Retrieve the system error message for the last-error code

    LPVOID lpMsgBuf;
    DWORD dw = errorCode;
    // LANG_ENGLISH, SUBLANG_ENGLISH_US
    // LANG_NEUTRAL, SUBLANG_DEFAULT
    if (FormatMessage(
            FORMAT_MESSAGE_ALLOCATE_BUFFER |
                FORMAT_MESSAGE_FROM_SYSTEM |
                FORMAT_MESSAGE_IGNORE_INSERTS,
            NULL,
            dw,
            MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
            (LPTSTR)&lpMsgBuf,
            0, NULL) == 0)
    {
        MessageBox(NULL, TEXT("FormatMessage failed"), TEXT("Error"), MB_OK);
        ExitProcess(dw);
    }

    // MessageBox(NULL, (LPCTSTR)lpMsgBuf, TEXT("Error"), MB_OK);
    printf("%s: %s\n", msg, lpMsgBuf);
    // Free the buffer allocated by the system

    LocalFree(lpMsgBuf);
    ExitProcess(dw);
}
